package com.quectel.cms.config.websocket;

import com.quectel.business.common.websocket.send.SendMsg;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * socket session
 *
 * @author: caolu
 * @email: louis.cao@quectel.com
 * @date: 2023-05-18 15:51:00
 */
@Slf4j
public class SocketSessionUtils {

    private static final ReentrantLock LOCK = new ReentrantLock();

    private static final String VILLAGE_KEY = "villageId";


    /**
     * 存放session的Map 三个值villageId token session 一个账号多个人登录就会产生多个session
     */
    private static final Map<Long, Map<String, WebSocketSession>> SESSION_MAP = new ConcurrentHashMap<>();


    /**
     * 注册一个通道
     *
     * @param villageId
     * @param token
     * @param webSocketSession
     */
    public static void registerSession(Long villageId, String token, WebSocketSession webSocketSession) {
        LOCK.lock();
        try {
            Map<String, WebSocketSession> socketMap = SESSION_MAP.get(villageId);
            if (socketMap == null) {
                socketMap = new HashMap<>();
                SESSION_MAP.put(villageId, socketMap);
            }
            WebSocketSession savedSession = socketMap.get(token);
            if (savedSession != null) {
                // 说明存在 需要先剔除后注册
                savedSession.close();
                socketMap.remove(token);
            }
            // session中绑定socket
            webSocketSession.getAttributes().put(VILLAGE_KEY, villageId);

            socketMap.put(token, webSocketSession);



        } catch (Exception e) {
            log.warn("Register websocket error", e);
        } finally {
            LOCK.unlock();
        }

    }

    /**
     * 向CMS发送消息 按照注册小区发送 多个登录客户端同时收到
     *
     * @param villageId
     * @param msgType
     * @param title
     * @param content
     * @param extParams
     * @see com.quectel.business.common.websocket.send.SendMsgType
     */
    public static void sendMsg(Long villageId, String msgType, String title, String content, Map<String, Object> extParams) {

        Map<String, WebSocketSession> savedSession = SESSION_MAP.get(villageId);
        if (savedSession == null || savedSession.size() == 0) {
            return;
        }
        for (WebSocketSession session : savedSession.values()) {
            try {
                session.sendMessage(new TextMessage(JacksonUtils.toJsonString(Response.ok().wrap(new SendMsg(villageId, msgType, title, content, extParams)))));
            } catch (Exception e) {
                log.warn("May be session closed", e);
            }
        }
    }

    /**
     * 向CMS发送消息 按照注册小区发送 只对主动发起方进行回复
     *
     * @param villageId
     * @param token
     * @param msgType
     * @param title
     * @param content
     * @param extParams
     * @see com.quectel.business.common.websocket.send.SendMsgType
     */
    public static void sendMsg(Long villageId, String token, String msgType, String title, String content, Map<String, Object> extParams) {
        Map<String, WebSocketSession> socketSessionMap = SESSION_MAP.get(villageId);
        if (socketSessionMap != null) {
            WebSocketSession webSocketSession = socketSessionMap.get(token);
            if (webSocketSession != null && webSocketSession.isOpen()) {
                try {
                    webSocketSession.sendMessage(new TextMessage(JacksonUtils.toJsonString(Response.ok().wrap(new SendMsg(villageId, msgType, title, content, extParams)))));
                } catch (IOException e) {
                    log.warn("May be session closed", e);
                }
            }
        }

    }

    public static void closeSession(WebSocketSession webSocketSession) {
        // 首先关闭session
        try {
            webSocketSession.close();
        } catch (Exception e) {
            log.warn("Close web socket error", e);
        }

        LOCK.lock();
        try {
            Long villageId = Long.valueOf(String.valueOf(webSocketSession.getAttributes().get(VILLAGE_KEY)));
            Map<String, WebSocketSession> socketMap = SESSION_MAP.get(villageId);
            if (socketMap != null) {
                socketMap.values().removeIf(session -> session == webSocketSession || !session.isOpen());
                if (socketMap.size() == 0) {
                    // 如果village下没有session那么也不需要保存socketMap
                    SESSION_MAP.remove(villageId);
                }
            }
        } catch (Exception e) {
            log.warn("Close session error");
        } finally {
            LOCK.unlock();
        }
    }


}
